/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package simulator.statistics;

import java.util.HashMap;
import java.util.Random;
import simulator.services.Clock;

/**
 *
 * @author Eran
 */
public class Utility {

    /**
     * A random-variable that should be used by any class in the entire project
     * (if necessary).
     */
    public static final Random rand = new Random(17);

    /**
     * Holds the number of agents, ticks that will be simulated, percentage of
     * electric cars, input and output files.
     */
    public static int SIMULATOR_AGENTS = 100;
    public static int SIMULATOR_TICKS = 1000;
    public static double SIMULATOR_ELECTRIC = 0.5;
    public static String SIMULATOR_FILE = String.format("file_%da_%dt.bin", Utility.SIMULATOR_AGENTS, Utility.SIMULATOR_TICKS);
    public static String SIMULATOR_MAP = "graph_tlv.txt";

    /**
     * Print debug messages along the simulator.
     */
    public static final boolean SIMULATOR_DEBUG = false;

    /**
     * Holds the length of a car (in order to avoid collisions).
     */
    public static final double CAR_LENGTH = 4.5;

    /**
     * Supposed to hold the driving speed (??). Not used currently.
     */
    public static final double CAR_KMPH = 10;

    /**
     * The probability of a worker to be sick in a given day.
     */
    public static final double PROB_SICKNESS = 0.049;

    /**
     * The employment ratio.
     */
    public static double SIMULATOR_EMPLOYMENT_RATIO = 93.8;

    /**
     * The time-slice of a traffic-light to be green.
     */
    public static final int TL_INTERVAL = 20;

    /**
     * Used to assign random capacities (in a pre-defined range) to parking
     * lots. (UNINITIALIZED).
     */
    public static final int LOT_MIN_CAPACITY = 375;
    public static final int LOT_MAX_CAPACITY = 500;

    /**
     * For some vertex v, defines the radius (meters) of search for a parking
     * lot close to v.
     */
    public static final double RADIUS_SEARCH = 250;

    /**
     * Defines the accuracy of the tagging process of parking lots. Each vertex
     * within the targeting radius (meters) of some other vertex with the
     * "parking_lot" tag is considered a parking lot. Of course, the smaller the
     * radius, the more accurate it will become.
     */
    public static final double RADIUS_TAGGING = 50;
//    public static final double RADIUS_TAGGING = 7.5;

    /**
     * Sleeping hours of a man.
     */
    private static final int[] sleepingHours = {10, 0, 0};

    /**
     * Each of the values 0,1,2 means that a tick is interpreted as a single
     * hour / minute / second respectively.
     */
    public static final int TICK_CONVERSION = 1;
    
    private static final double[]hourCasting = {1.0, 60.0, 3600.0};
    private static final double hour_to_tick = hourCasting[TICK_CONVERSION];

    public static double TANK_CRITICAL = 0.25;
    /**
     * Consumption ratios: fuel (liter/meters) and electricity (watt/meters).
     */
    public static double ELECTRICITY_CONSUMPTION_RATIO = 0.000625;
    public static double FUEL_CONSUMPTION_RATIO = 0.000125;

    /**
     * Battery recharge-rate and Fuel-tank filling-rate (liter per hour).
     */
    public static double ELECTRICITY_RECHARGE_RATE = 100.0 / hour_to_tick;
    public static double FUEL_RECHARGE_RATE = (50*15.0) / hour_to_tick;

    /**
     * Fuel tank capacity (liters).
     */
    private static double TANK_CAPACITY_FUEL = 50;

    /**
     * Battery capacity (percentage).
     */
    private static double TANK_CAPACITY_ELECTRICITY = 100;

    /**
     * Probability of willing to go have fun (restaurant/ movie/ shopping/etc.).
     */
    public static double PROB_FUN = 1.0 / Math.pow(2, 3);

    /**
     * Calculate the car's speed on the current road-segment. (UNINITIALIZED)
     *
     * @param edgeAttr
     * @param length
     * @return
     */
    public static double calculateCarSpeed(HashMap<String, String> edgeAttr, double length) {
        /**
         * convert km/hour to meter/(hour/min/sec - depends on the meaning of
         * tick at the simulation). km/hour = 1000/1 * meter/hour = 1000/60 *
         * meter/minute = 1000/(60*60) * meter/second.
         */
        double factor = 1000.0 / Utility.hour_to_tick;
        double speed;

        switch (edgeAttr.get("highway")) {
            case "motorway":
                speed = factor * 105;
                break;
            case "trunk":
                speed = factor * 90;
                break;
            case "primary":
                speed = factor * 50;
                break;
            case "secondary":
                speed = factor * 50;
                break;
            case "tertiary":
                speed = factor * 50;
                break;
            case "unclassified":
                speed = factor * 50;
                break;
            case "residential":
                speed = factor * 50;
                break;
            case "living_street":
                speed = factor * 30;
                break;
            default:
                return 100;
        }
        if (length < speed) {
            speed = 100;
        } else {
            speed = (speed / length) * 100;
        }
//        speed = 100;

        return speed;
    }

    /**
     * Calculate the maximal capacity of a given road (not sure this is
     * necessary, maybe just generate random value from the given interval).
     * (UNINITIALIZED)
     *
     * @param edgeAttr
     * @return
     */
    public static int calculateSegmentCapacity(HashMap<String, String> edgeAttr) {
        return 1353543481;
    }

    /**
     * Calculate the traffic-light's time-slice to be green. Maybe can generate
     * random values within a range. (UNINITIALIZED).
     *
     * @return
     */
    public static int calculate_TLInterval() {
        return TL_INTERVAL;
    }

    /**
     * Calculate capacity for some parking lot.
     *
     * @return
     */
    public static int calculateLotCapacity() {
        return LOT_MIN_CAPACITY + rand.nextInt(LOT_MAX_CAPACITY - LOT_MIN_CAPACITY);
    }

    
    private static final int[] min_exitHour = {6,45};
    private static final int[] max_exitHour = {7,35};
    /**
     * Calculates a worker's daily schedule at work: when to leave home
     * (array[0]) and how many hours to work (array[1]). This is an alternative
     * solution to the method calculateWorkHours(). (UNINITIALIZED).
     *
     * @return
     */
    public static Clock[] generateDailySchedule() {
        Clock workHours = new Clock(7,15);
        
//        Clock exitHour = new Clock(7, 30);
        Clock exitHour = Clock.generateRandomClock(min_exitHour, max_exitHour);
        return new Clock[]{exitHour, workHours};
    }

    /**
     * Generate a sleeping hour for a man. If he is a worker
     * (leavingHour!=null), than his leavingHour need to be considered.
     * Otherwise, calculate by some other formula.
     *
     * @param leavingHour
     * @return
     */
    public static Clock generateStartSleepingHour(Clock leavingHour) {
        if (leavingHour == null) {
            return new Clock(23, 20);
        }

        int[] sleepHour = Clock.subtractClocks(Utility.sleepingHours, leavingHour.toArray());
//        System.out.printf("%d:%d:%d\n", sleepHour[0], sleepHour[1], sleepHour[2]);
        return new Clock(sleepHour);
    }

    /**
     * Generate time for spending time (at a restaurant/shop/cinema, etc.).
     *
     * @param cl
     */
    public static void generateSpendingTime(Clock cl) {
        cl.set(1, 15);
    }

    /**
     * Check that the current time is not in the middle of a sleeping process.
     *
     * @param sleep
     * @param currTime
     * @return
     */
    public static boolean inSleepingInterval(String sleep, String currTime) {
        int[] start = Clock.parseStringClock(sleep);
        int[] curr = Clock.parseStringClock(currTime);
        int[] passed = Clock.subtractClocks(start, curr);

        for (int i = 0; i < passed.length; i++) {
            if (sleepingHours[i] > passed[i]) {
                return true;
            }
            if (sleepingHours[i] < passed[i]) {
                return false;
            }
        }
        return true;

    }

    public static double generateCapacity(boolean electric) {
        if (electric) {
            return Utility.TANK_CAPACITY_ELECTRICITY;
        } else {
            return Utility.TANK_CAPACITY_FUEL;
        }
    }

    /**
     * Determine the type of a new car - electric or not.
     *
     * @return
     */
    public static boolean generateCarType() {
        return (rand.nextDouble() < SIMULATOR_ELECTRIC);
    }
}
